#pragma once

#include "httplib.h"
#include "data.hpp"

namespace aod
{
#define WWW_ROOT "./www"
#define VIDEO_ROOT "/video/"
#define IMAGE_ROOT "/image/"

    // 因为httplib基于多线程，因此数据管理对象需要在多线程中访问，为了便于访问定义全局变量
    TableVideo *tb_video = NULL;

    // 这⾥为了更加功能模块划分清晰⼀些，不使⽤lamda表达式完成，否则所有的功能实现集中到⼀个函数中太过庞⼤
    class Server
    {
    public:
        Server(int port) : _port(port) {}
        // 建⽴请求与处理函数的映射关系，设置静态资源根⽬录，启动服务器，
        bool RunModule()
        {
            // 1.初始化操作--初始化数据管理模块，创建指定目录
            tb_video = new TableVideo();
            FileUtil(WWW_ROOT).CreateDirectory();
            std::string root = WWW_ROOT;
            std::string video_real_path = root + VIDEO_ROOT; // ./www/video/
            FileUtil(video_real_path).CreateDirectory();
            std::string image_real_path = root + IMAGE_ROOT; // ./www/image/
            FileUtil(image_real_path).CreateDirectory();

            // 2.搭建http服务器，开始运行
            //     1.设置静态资源根目录
            _srv.set_mount_point("/", WWW_ROOT);
            //     2.添加请求-处理函数映射关系
            _srv.Post("/video", Insert);
            _srv.Delete("/video/(\\d+)", Delete);
            _srv.Put("/video/(\\d+)", Update);
            _srv.Get("/video/(\\d+)", SelectOne);
            _srv.Get("/video/", SelectAll);
            //     3.启动服务器
            std::cout << "启动服务器...." << std::endl;

            _srv.listen("0.0.0.0", _port);


            return true;

            // 启动服务器后，httplib在收到请求之后，首先查看请求的方法与资源路径，看映射关系里面有没有
            // 对应的函数处理，如果有，就调用对应的处理函数进行处理，如果没有，再查看请求的是否是静态资源，
            // 就是查看www目录下有没有对应的文件，如果有就进行响应，如果没有就返回404
        }

    private:
        // 对应的业务处理接⼝
        static void Insert(const httplib::Request &req, httplib::Response &rsp)
        {
            std::cout << "执行到了这里Insert" << std::endl;

            if (req.has_file("name") == false ||
                req.has_file("info") == false ||
                req.has_file("video") == false ||
                req.has_file("image") == false)
            {

                rsp.status = 400;
                rsp.body = R"({"result":false, "reason":"上传的数据信息错误"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            httplib::MultipartFormData name = req.get_file_value("name");   // 视频名称
            httplib::MultipartFormData info = req.get_file_value("info");   // 视频简介
            httplib::MultipartFormData video = req.get_file_value("video"); // 视频文件
            httplib::MultipartFormData image = req.get_file_value("image"); // 图片文件

            // MultipartFormData {name-字段名, content_type-正文类型, filename-原始文件xx.jpg, content-正文}
            std::string video_name = name.content;
            std::string video_info = info.content;
            // ./www/image/变形金刚a.jpg
            std::string root = WWW_ROOT;
            std::string video_path = root + VIDEO_ROOT + video_name + video.filename;
            std::string image_path = root + IMAGE_ROOT + video_name + image.filename;

            // 向文件写入数据
            if (FileUtil(video_path).SetContent(video.content) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"视频文件存储失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }

            if (FileUtil(image_path).SetContent(image.content) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"图片文件存储失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }

            // 把上传的数据插入数据库
            Json::Value video_json;
            video_json["name"] = video_name;
            video_json["info"] = video_info;
            video_json["video"] = VIDEO_ROOT + video_name + video.filename; // /video/变形金刚robot.mp4
            video_json["image"] = IMAGE_ROOT + video_name + image.filename; // /video/变形金刚robot.mp4
            if (tb_video->Insert(video_json) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"数据库新增数据失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            rsp.set_redirect("/index.html", 303);

            return;
        }

        static void Update(const httplib::Request &req, httplib::Response &rsp)
        {
            std::cout << "执行到了这里Update" << std::endl;

            // 1. 获取要修改的视频信息 (1).视频id， (2).修改后的信息
            int video_id = std::stoi(req.matches[1]);
            Json::Value video;
            // 先要反序列化，而不是直接使用字符串，得到的json::value数据放在video里
            if (JsonUtil::UnSerialize(req.body, &video) == false)
            {
                rsp.status = 400;
                rsp.body = R"({"result":false, "reason":"新的视频信息格式解析失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            // 2. 修改数据库数据
            if (tb_video->Update(video_id, video) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"修改数据库信息失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            return;
        }

        static void Delete(const httplib::Request &req, httplib::Response &rsp)
        {
            std::cout << "执行到了这里Delete" << std::endl;

            // 1.获取要删除的视频ID
            int video_id = std::stoi(req.matches[1]);
            // 2.删除视频文件，封面图片
            Json::Value video;
            if (tb_video->SelectOne(video_id, &video) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"不存在视频信息"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            // 获取实际存储路径
            std::string root = WWW_ROOT;
            std::string video_path = root + video["video"].asString();
            std::string image_path = root + video["image"].asString();
            remove(video_path.c_str());
            remove(image_path.c_str());
            // 3.删除数据库信息
            if (tb_video->Delete(video_id) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"删除数据库信息失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            return;
        }

        static void SelectOne(const httplib::Request &req, httplib::Response &rsp)
        {
            std::cout << "执行到了这里SelectOne" << std::endl;

            // 1. 获取视频的ID
            int video_id = std::stoi(req.matches[1]);
            // 2. 在数据库中查询指定视频信息
            Json::Value video;
            if (tb_video->SelectOne(video_id, &video) == false)
            {
                rsp.status = 500;
                rsp.body = R"({"result":false, "reason":"查询数据库指定视频信息失败"})";
                rsp.set_header("Content-Type", "application/json");
                return;
            }
            // 3. 组织响应正文--json格式的字符串
            JsonUtil::Serialize(video, &rsp.body);
            rsp.set_header("Content-Type", "application/json"); // 设置头部信息
            return;
        }

        static void SelectAll(const httplib::Request &req, httplib::Response &rsp)
        {
            std::cout << "执行到了这里SelectAll" << std::endl;
            // /video   &    /video?search="关键字"
            bool select_flag = true; // 默认所有查询
            std::string search_key;
            // 先判断搜索的关键词在不在
            if (req.has_param("search") == true)
            {
                select_flag = false; // 模糊匹配
                search_key = req.get_param_value("search");
            }
            // 分情况讨论查询所有或是模糊匹配
            Json::Value videos;
            if (select_flag == true)
            {
                if (tb_video->SelectAll(&videos) == false)
                {
                    rsp.status = 500;
                    rsp.body = R"({"result":false, "reason":"查询数据库所有视频信息失败"})";
                    rsp.set_header("Content-Type", "application/json");
                    return;
                }
            }
            else
            {
                if (tb_video->SelectLike(search_key, &videos) == false)
                {
                    rsp.status = 500;
                    rsp.body = R"({"result":false, "reason":"查询数据库匹配视频信息失败"})";
                    rsp.set_header("Content-Type", "application/json");
                    return;
                }
            }
            // 组织响应正文
            JsonUtil::Serialize(videos, &rsp.body);
            rsp.set_header("Content-Type", "application/json");
            return;
        }

    private:
        int _port;            // 服务器的 监听端⼝
        httplib::Server _srv; // ⽤于搭建http服务器
    };
}